package kayao.server;

import kayao.common.KayaoValues;
import java.util.Vector;

public class AreaManager {
	private static Region[] sRegions;
	private static Vector<Vector<Integer>> sSlaves= new Vector<Vector<Integer>>();
	public static Object sRegionsLock=new Object();
	private static int sCurrentRegion = 0;
	
	public static void initialize() {
		// Calculate number of regions
		if (KayaoValues.NUM_REGIONS_X == 1) { KayaoValues.NUMBER_OF_KINGDOMS = KayaoValues.NUM_REGIONS_Y; }
		else if (KayaoValues.NUM_REGIONS_X % 2 == 0) { KayaoValues.NUMBER_OF_KINGDOMS = (KayaoValues.NUM_REGIONS_X/2) * KayaoValues.NUM_REGIONS_Y + (KayaoValues.NUM_REGIONS_X/2) * (KayaoValues.NUM_REGIONS_Y+1); }
		else { KayaoValues.NUMBER_OF_KINGDOMS = (KayaoValues.NUM_REGIONS_X/2+1) * KayaoValues.NUM_REGIONS_Y + (KayaoValues.NUM_REGIONS_X/2) * (KayaoValues.NUM_REGIONS_Y+1); }
		// Create an array to store the regions
		sRegions = new Region[KayaoValues.NUMBER_OF_KINGDOMS];
		for(int i=0;i<KayaoValues.NUMBER_OF_KINGDOMS;i++)
			sSlaves.add(new Vector<Integer>());
		// Now create the regions
		float width;
		float height;
		int counter = 0;
		for (int i = 0; i < KayaoValues.NUM_REGIONS_X; i++) {
			// column 0 2 4 etc..
			if (i % 2 == 0){
				for (int j = 0; j < KayaoValues.NUM_REGIONS_Y; j++) {				
					width = KayaoValues.TOTAL_MAP_WIDTH/KayaoValues.NUM_REGIONS_X;
					height = KayaoValues.TOTAL_MAP_HEIGHT/KayaoValues.NUM_REGIONS_Y;
					sRegions[counter] = new Region(i*width, j*height, (i+1)*width, (j+1)*height);
					counter++;
				}
			// column 1 3 5 etc..
			} else {
				for (int j = 0; j < (KayaoValues.NUM_REGIONS_Y+1); j++) {
					width = KayaoValues.TOTAL_MAP_WIDTH/KayaoValues.NUM_REGIONS_X;
					height = KayaoValues.TOTAL_MAP_HEIGHT/(KayaoValues.NUM_REGIONS_Y);						
					// first region
					if (j == 0){
						sRegions[counter] = new Region(i*width, j*height, (i+1)*width, height/2);
					// last region
					} else if (j == KayaoValues.NUM_REGIONS_Y){
						sRegions[counter] = new Region(i*width, (j-1)*height+height/2, (i+1)*width, j*height);
					// regions in between
					} else {
						sRegions[counter] = new Region(i*width, (j-1)*height+height/2, (i+1)*width, j*height+height/2);
					}
					counter++;
				}
			}
		}
	}


	public static void setCurrentRegion(int region) {
		synchronized(sRegionsLock){
			sCurrentRegion = region;
		}
	}

	public static int getCurrentRegion() {
		synchronized(sRegionsLock){
			return sCurrentRegion;
		}
	}

	public static void printRegions() {
		synchronized(sRegionsLock){
			for (int i = 0; i < sRegions.length; i++) {
				System.out.println("Region "+i+" "+sRegions[i].toString());
			}
		}
	}
	public static String getRegions() {
		synchronized(sRegionsLock){
			String out = "";
			for (int i = 0; i < sRegions.length; i++) {
				out = out+"Region "+i+"\t"+sRegions[i].toString()+"\n";
			}
			return out;
		}
	}

	public static void deleteKingById(int id){
		synchronized(sRegionsLock){
			for (int i = 0; i < sRegions.length; i++) {
				if (id == sRegions[i].getKing()){ sRegions[i].removeKing(); break; }
			}
		}
	}

	public static int getKingByRegion(int region){
		synchronized(sRegionsLock){
			return sRegions[region].getKing();
		}
	}
	
	/**
	 * It checks out the kings. In case there's no king, it creates one with the ID of the client 
	 * that requests it if it belongs to that region.
	 * @param clientid: ID of the client who is asking
	 * @param currentRegion: The current region of the client who is asking
	 * @param wantedRegion: The region of interest
	 * @return the king id. 0 if there's no king
	 */
	public synchronized static int checkKing(int clientid, int currentRegion, int wantedRegion) {
		synchronized(sRegionsLock){
			try{
				// If the wanted region has no king
				if (sRegions[wantedRegion].getKing() == 0)
				{
					// Assign the client as king if he is currently inside it
					if (currentRegion == wantedRegion)
					{
						sRegions[wantedRegion].setKing(clientid);
						//tell everybody I'm not the virtual king anymore
						DesktopServer.tellImNotYourKing(sSlaves.get(wantedRegion),wantedRegion);
						//clean the list 
						sSlaves.get(wantedRegion).removeAllElements();
						return clientid;
					}
					// Otherwise leave the region without king and keep track of him
					else 
					{
						addSlave(sSlaves.get(wantedRegion),clientid);
						return 0;
					}
				}
				// If the region has a king assigned, just return its id
				else 
				{
					return sRegions[wantedRegion].getKing();
				}
			} catch(Exception e) {
				System.out.println("[Server] (AreaManager) checkKing: " +e.getMessage());
				return 0;
			}
		}
	}


	private static void addSlave(Vector<Integer> vector, int clientid) {
		for(int i=0;i<vector.size();i++)
			if(vector.get(i)==clientid)
				return;
		vector.add(clientid);
		
	}


	public static void removeInterestInRegions(int id, Vector<Integer> regions) 
	{
		//for each region in the map
		for(int i=0;i<sRegions.length;i++)
		{
			boolean interested=false;
			//for each region interested
			for(int j=0;j<regions.size();j++)
			{
				if(regions.get(j)==i)
				{
					interested=true;
					break;
				}
			}
			//if we're not interested we delete ourselves
			if(!interested)
			{
				//we look for us in the list
				for(int k=0;k<sSlaves.get(i).size();k++)
				{
					//if we find us
					if(sSlaves.get(i).get(k)==id)
					{
						//System.out.println("[AreaManager] - ID: "+ id+ ", is not interested in" +
						//		" region "+ i+" anymore");
						sSlaves.get(i).remove(k);
						break;
					}
				}	
			}
		}
		
	}
}
